﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.ExtensibleStorage;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YArchitech.Temp;
using Microsoft.CSharp.RuntimeBinder;

namespace YArchitech.Plumbing
{
	internal static class RevitUtils
	{
		public static double GetConnectorAngle(Connector conn1, Connector conn2)
		{
			XYZ basisZ = conn1.CoordinateSystem.BasisZ;
			XYZ basisZ2 = conn1.CoordinateSystem.BasisZ;
			return basisZ.AngleTo(basisZ2);
		}

		public static double GetDistance(Connector con1, Connector con2)
		{
			return RevitUtils.DistanceToInternal(con1.Origin.DistanceTo(con2.Origin));
		}

		public static bool IsLink(Connector con1, Connector con2)
		{
			return con1 != null && con2 != null && (con1.IsConnectedTo(con2) || con1.Origin.DistanceTo(con2.Origin) < RevitUtils.Tol);
		}

		public static ConnectorManager GetElementConnectorManager(Element element)
		{
			ConnectorManager connectorManager;
			if (element is FamilyInstance)
			{
				connectorManager = (element as FamilyInstance).MEPModel.ConnectorManager;
			}
			else
			{
				connectorManager = (element as MEPCurve).ConnectorManager;
			}
			return connectorManager;
		}

		public static List<Connector> GetElementConnectors(Element element)
		{
			ConnectorManager elementConnectorManager = RevitUtils.GetElementConnectorManager(element);
			if (elementConnectorManager == null)
			{
				return null;
			}
			List<Connector> list = new List<Connector>();
			foreach (object obj in elementConnectorManager.Connectors)
			{
				Connector item = (Connector)obj;
				list.Add(item);
			}
			return list;
		}

		public static Connector GetConnectedConnector(Connector connector)
		{
			if (connector == null)
			{
				return null;
			}
			Connector result = null;
			foreach (object obj in connector.AllRefs)
			{
				Connector connector2 = (Connector)obj;
				if ((int)connector2.ConnectorType == 1 && !connector2.Owner.Id.IntegerValue.Equals(connector.Owner.Id.IntegerValue))
				{
					result = connector2;
					break;
				}
			}
			return result;
		}

		public static Connector GetOpenConnector(Element element, Connector inputConnector)
		{
			Connector connector = null;
			foreach (Connector connector2 in RevitUtils.GetElementConnectors(element))
			{
				if (inputConnector == null || !connector2.IsConnectedTo(inputConnector))
				{
					if (!connector2.IsConnected)
					{
						connector = connector2;
						break;
					}
					foreach (object obj in connector2.AllRefs)
					{
						Connector connector3 = (Connector)obj;
						if ((int)connector3.ConnectorType == 1 && !connector3.Owner.Id.IntegerValue.Equals(connector2.Owner.Id.IntegerValue) && (inputConnector == null || !connector3.Owner.Id.IntegerValue.Equals(inputConnector.Owner.Id.IntegerValue)))
						{
							connector = RevitUtils.GetOpenConnector(connector3.Owner, connector2);
							if (connector != null)
							{
								break;
							}
						}
					}
				}
			}
			return connector;
		}

		public static MEPSystem ExtractMechanicalOrPipingSystem(Element selectedElement)
		{
			MEPSystem result = null;
			if (selectedElement is MEPSystem)
			{
				if (selectedElement is MechanicalSystem || selectedElement is PipingSystem)
				{
					return selectedElement as MEPSystem;
				}
			}
			else
			{
				FamilyInstance familyInstance = selectedElement as FamilyInstance;
				if (familyInstance != null)
				{
					MEPModel mepmodel = familyInstance.MEPModel;
					ConnectorSet connectors = null;
					try
					{
						connectors = mepmodel.ConnectorManager.Connectors;
					}
					catch (Exception)
					{
					}
					result = RevitUtils.ExtractSystemFromConnectors(connectors);
				}
				else
				{
					MEPCurve mepcurve = selectedElement as MEPCurve;
					if (mepcurve != null)
					{
						result = RevitUtils.ExtractSystemFromConnectors(mepcurve.ConnectorManager.Connectors);
					}
				}
			}
			return result;
		}

		public static MEPSystem ExtractSystemFromConnectors(ConnectorSet connectors)
		{
			MEPSystem result = null;
			if (connectors == null || connectors.Size == 0)
			{
				return null;
			}
			List<MEPSystem> list = new List<MEPSystem>();
			foreach (object obj in connectors)
			{
				MEPSystem mepsystem = ((Connector)obj).MEPSystem;
				if (mepsystem != null)
				{
					MechanicalSystem mechanicalSystem = mepsystem as MechanicalSystem;
					if (mechanicalSystem != null)
					{
						if (mechanicalSystem.IsWellConnected)
						{
							list.Add(mepsystem);
						}
					}
					else
					{
						PipingSystem pipingSystem = mepsystem as PipingSystem;
						if (pipingSystem != null && pipingSystem.IsWellConnected)
						{
							list.Add(mepsystem);
						}
					}
				}
			}
			if (list.Count != 0)
			{
				int num = 0;
				foreach (MEPSystem mepsystem2 in list)
				{
					if (mepsystem2.Elements.Size > num)
					{
						result = mepsystem2;
						num = mepsystem2.Elements.Size;
					}
				}
			}
			return result;
		}

		public static void MatchConnector(Connector connModify, Connector connRef)
		{
			if (connModify.Shape == null)
			{
				connModify.Radius = connRef.Radius;
				return;
			}
			XYZ basisX = connRef.CoordinateSystem.BasisX;
			if (RevitUtils.IsParallel(connModify.CoordinateSystem.BasisX, basisX))
			{
				connModify.Width = connRef.Width;
				connModify.Height = connRef.Height;
				return;
			}
			connModify.Height = connRef.Width;
			connModify.Width = connRef.Height;
		}

		public static void SetConnectorSize(Connector connector, double WidthOrDia, double Height)
		{
			if (connector.Shape == null)
			{
				connector.Radius = WidthOrDia / 2.0;
				return;
			}
			if (connector.Width < connector.Height)
			{
				connector.Width = Height;
				connector.Height = WidthOrDia;
				return;
			}
			connector.Width = WidthOrDia;
			connector.Height = Height;
		}

		public static double GetFamilyCoefficient(FamilyInstance fi)
		{
			return RevitUtils.GetValue(fi, BuiltInParameter.RBS_PIPE_FITTING_LOSS_KFACTOR_PARAM);
		}

		public static string GetFamilyInstanceName(FamilyInstance fi)
		{
			if (fi == null)
			{
				return string.Empty;
			}
			string name = fi.Name;
			return fi.Symbol.Family.Name + "/" + name;
		}

		public static bool IsPipeSystemObject(Element elem)
		{
			return DbUtils.IsPipe(elem) || DbUtils.IsPipeAccessory(elem) || DbUtils.IsPipeFitting(elem) || DbUtils.IsMechanicalEquipment(elem);
		}

		public static Element GetElementById(Autodesk.Revit.DB.Document doc, ElementId id)
		{
			return doc.GetElementById(id);
		}

		public static void HighLight(UIDocument uiDoc, ElementId id)
		{
			Element elementById = RevitUtils.GetElementById(uiDoc.Document, id);
			RevitUtils.HighLight(uiDoc, elementById);
		}

		public static void HighLight(UIDocument uiDoc, Element element)
		{
			if (element == null)
			{
				return;
			}
			RevitVersionFuncs.ClearSelection(uiDoc.Selection);
			RevitVersionFuncs.AddToSelection(uiDoc.Selection, element);
		}

		public static void HighLight(UIDocument uiDoc, ICollection<ElementId> ids)
		{
			RevitVersionFuncs.ClearSelection(uiDoc.Selection);
			List<Element> list = new List<Element>();
			foreach (ElementId id in ids)
			{
				Element elementById = RevitUtils.GetElementById(uiDoc.Document, id);
				if (elementById != null)
				{
					list.Add(elementById);
				}
			}
			RevitVersionFuncs.SetSelection(uiDoc.Selection, list);
		}

		public static void HighLight(UIDocument uiDoc, ICollection<Element> elements)
		{
			RevitVersionFuncs.ClearSelection(uiDoc.Selection);
			List<Element> list = new List<Element>();
			foreach (Element item in elements)
			{
				list.Add(item);
			}
			RevitVersionFuncs.SetSelection(uiDoc.Selection, list);
		}

		public static bool IsParallel(XYZ vec1, XYZ vec2)
		{
			XYZ xyz = vec1.Normalize();
			XYZ xyz2 = vec2.Normalize();
			return xyz.IsAlmostEqualTo(xyz2) || xyz.IsAlmostEqualTo(xyz2.Negate());
		}

		public static bool IsPerpendicular(XYZ vec1, XYZ vec2)
		{
			return Math.PI*.5 - vec1.AngleTo(vec2) < 0.0001;
		}

		public static bool IsParallelToXYPlane(XYZ vec)
		{
			XYZ basisX = XYZ.BasisX;
			XYZ basisY = XYZ.BasisY;
			XYZ basisZ = XYZ.BasisZ;
			return Math.Abs(vec.Z) < 0.0001;
		}

		public static string GetSystemName(Element elem)
		{
			Parameter parameter = elem.GetParameter(BuiltInParameter.RBS_SYSTEM_NAME_PARAM);
			if (parameter == null)
			{
				return "空调水系统";
			}
			return parameter.AsString();
		}

		public static bool GetPipeSystemType(Element elem)
		{
			Parameter parameter = elem.GetParameter(BuiltInParameter.RBS_PIPING_SYSTEM_TYPE_PARAM);
			if (parameter == null)
			{
				return false;
			}
			ElementId elementId = parameter.AsElementId();
			PipingSystem pipingSystem = elem.Document.GetElementById(elementId) as PipingSystem;
			return false;
		}

		public static double GetAngle(FamilyInstance fi)
		{
			double result = Math.PI*.5;
			Parameter parameter = fi.GetParameter("角度");
			if (parameter == null)
			{
				parameter = fi.GetParameter("Angle");
			}
			if (parameter != null)
			{
				result = parameter.AsDouble();
			}
			return result;
		}

		public static double GetValue(Element elem, BuiltInParameter builtInParam)
		{
			Parameter parameter = elem.GetParameter(builtInParam);
			if (parameter == null)
			{
				return 0.0;
			}
			return parameter.AsDouble();
		}

		public static string GetRevitNumber(Element elem)
		{
			if (elem is Pipe || elem is FlexPipe)
			{
				Parameter parameter = elem.GetParameter(BuiltInParameter.DOOR_NUMBER);
				if (parameter != null && parameter.HasValue)
				{
					return parameter.AsString();
				}
			}
			return "";
		}

		public static void SetValue(Element elem, BuiltInParameter builtInParam, double valueImperial)
		{
			Parameter parameter = elem.GetParameter(builtInParam);
			if (parameter != null)
			{
				parameter.Set(valueImperial);
			}
		}

		public static double GetDistance(Element elem, BuiltInParameter builtInParam)
		{
			return RevitUtils.DistanceToInternal(RevitUtils.GetValue(elem, builtInParam));
		}

		public static double GetPipeLevelElevation(Element elem)
		{
			double result = 0.0;
			Parameter parameter = elem.GetParameter(BuiltInParameter.RBS_START_LEVEL_PARAM);
			if (parameter != null)
			{
				Level level = elem.Document.GetElementById(parameter.AsElementId()) as Level;
				if (level != null)
				{
					result = UnitConvert.CovertFromAPI((Autodesk.Revit.DB.DisplayUnitType)0, level.Elevation);
				}
			}
			return result;
		}

		public static double GetSharaParameter(Element elem, BuiltInParameter builtInParam, DisplayUnitType UnitType)
		{
			double value = RevitUtils.GetValue(elem, builtInParam);
			return UnitConvert.CovertFromAPI(UnitType, value);
		}

		public static double GetSharaParameter(Element elem, string paramName, DisplayUnitType UnitType)
		{
			Parameter parameter = elem.GetParameter(paramName);
			if (parameter == null)
			{
				return 0.0;
			}
			double value = parameter.AsDouble();
			return UnitConvert.CovertFromAPI(UnitType, value);
		}

		public static double GetCurveLength(Element elem, BuiltInParameter builtInParam = BuiltInParameter.CURVE_ELEM_LENGTH)
		{
			return RevitUtils.GetDistance(elem, builtInParam);
		}

		public static double GetVelocity(Element elem, BuiltInParameter builtInParam = BuiltInParameter.RBS_PIPE_VELOCITY_PARAM)
		{
			return RevitUtils.VelocityToInternal(RevitUtils.GetValue(elem, builtInParam));
		}

		public static double GetFlow(Element elem, BuiltInParameter builtInParam = BuiltInParameter.RBS_PIPE_FLOW_PARAM)
		{
			return RevitUtils.FlowToInternal(RevitUtils.GetValue(elem, builtInParam));
		}

		public static double GetRm(Element elem, BuiltInParameter builtInParam = BuiltInParameter.RBS_PIPE_FRICTION_PARAM)
		{
			double value = RevitUtils.GetValue(elem, builtInParam);
			return UnitConvert.CovertFromAPI((Autodesk.Revit.DB.DisplayUnitType)38, value);
		}

		public static double GetPressure(Element elem, BuiltInParameter builtInParam)
		{
			return RevitUtils.PressureToInternal(RevitUtils.GetValue(elem, builtInParam));
		}

		public static double GetRoughness(Pipe revitPipe, BuiltInParameter builtInParam = BuiltInParameter.RBS_PIPE_ROUGHNESS_PARAM)
		{
			return RevitUtils.DistanceToInternal(RevitUtils.GetValue(revitPipe, BuiltInParameter.RBS_PIPE_ROUGHNESS_PARAM));
		}

		public static double GetRoughness(FlexPipe revitPipe, BuiltInParameter builtInParam = BuiltInParameter.RBS_PIPE_ROUGHNESS_PARAM)
		{
			return RevitUtils.DistanceToInternal(RevitUtils.GetValue(revitPipe, BuiltInParameter.RBS_PIPE_ROUGHNESS_PARAM));
		}

		public static void SetDistance(Element elem, BuiltInParameter builtInParam, double value)
		{
			double valueImperial = RevitUtils.DistanceToStd(value);
			RevitUtils.SetValue(elem, builtInParam, valueImperial);
		}

		public static void SetVelocity(Element elem, BuiltInParameter builtInParam, double value)
		{
			double valueImperial = RevitUtils.VelocityToStd(value);
			RevitUtils.SetValue(elem, builtInParam, valueImperial);
		}

		public static void SetFlow(Element elem, BuiltInParameter builtInParam, double value)
		{
			double valueImperial = RevitUtils.FlowToStd(value);
			RevitUtils.SetValue(elem, builtInParam, valueImperial);
		}

		public static double Fix(double d, int prec = 3)
		{
			double num = Math.Pow(10.0, (double)prec);
			return Math.Round(d * num + 0.5) / num;
		}

		public static double DistanceToStd(double meters)
		{
			return UnitConvert.CovertToAPI(meters, (Autodesk.Revit.DB.DisplayUnitType)0);
		}

		public static double DistanceToInternal(double imperial)
		{
			return UnitConvert.CovertFromAPI((Autodesk.Revit.DB.DisplayUnitType)0, imperial);
		}

		public static double VelocityToStd(double meterPerSecond)
		{
			return UnitConvert.CovertToAPI(meterPerSecond, (Autodesk.Revit.DB.DisplayUnitType)61);
		}

		public static double VelocityToInternal(double feetPerSecord)
		{
			return UnitConvert.CovertFromAPI((Autodesk.Revit.DB.DisplayUnitType)61, feetPerSecord);
		}

		public static double FlowToStd(double cubicMetersPerSecond)
		{
			return UnitConvert.CovertToAPI(cubicMetersPerSecond, (Autodesk.Revit.DB.DisplayUnitType)65);
		}

		public static double FlowToInternal(double cubicFeetPerMinute)
		{
			return UnitConvert.CovertFromAPI((Autodesk.Revit.DB.DisplayUnitType)65, cubicFeetPerMinute);
		}

		public static double PressureToStd(double poundPerSuqreFoot)
		{
			return UnitConvert.CovertToAPI(poundPerSuqreFoot, (Autodesk.Revit.DB.DisplayUnitType)48);
		}

		public static double PressureToInternal(double poundPerSuqreFoot)
		{
			return UnitConvert.CovertFromAPI((Autodesk.Revit.DB.DisplayUnitType)48, poundPerSuqreFoot);
		}

		public static Connector GetMEPObjectConnector(dynamic rvtMEPModel)
		{
			Connector result = null;
			if (RevitUtils.<>o__53.<>p__2 == null)
			{
				RevitUtils.<>o__53.<>p__2 = CallSite<Func<CallSite, object, IEnumerable>>.Create(Binder.Convert(CSharpBinderFlags.None, typeof(IEnumerable), typeof(RevitUtils)));
			}
			Func<CallSite, object, IEnumerable> target = RevitUtils.<>o__53.<>p__2.Target;
			CallSite <>p__ = RevitUtils.<>o__53.<>p__2;
			if (RevitUtils.<>o__53.<>p__1 == null)
			{
				RevitUtils.<>o__53.<>p__1 = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, "Connectors", typeof(RevitUtils), new CSharpArgumentInfo[]
				{
					CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
				}));
			}
			Func<CallSite, object, object> target2 = RevitUtils.<>o__53.<>p__1.Target;
			CallSite <>p__2 = RevitUtils.<>o__53.<>p__1;
			if (RevitUtils.<>o__53.<>p__0 == null)
			{
				RevitUtils.<>o__53.<>p__0 = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, "ConnectorManager", typeof(RevitUtils), new CSharpArgumentInfo[]
				{
					CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
				}));
			}
			IEnumerator enumerator = target(<>p__, target2(<>p__2, RevitUtils.<>o__53.<>p__0.Target(RevitUtils.<>o__53.<>p__0, rvtMEPModel))).GetEnumerator();
			{
				if (enumerator.MoveNext())
				{
					if (RevitUtils.<>o__53.<>p__3 == null)
					{
						RevitUtils.<>o__53.<>p__3 = CallSite<Func<CallSite, object, Connector>>.Create(Binder.Convert(CSharpBinderFlags.ConvertExplicit, typeof(Connector), typeof(RevitUtils)));
					}
					result = RevitUtils.<>o__53.<>p__3.Target(RevitUtils.<>o__53.<>p__3, enumerator.Current);
				}
			}
			return result;
		}

		public static bool UpdateSection(ref HYPipeSpecification ds, Connector conn, bool vertical = false)
		{
			if (conn == null || ds == null)
			{
				return false;
			}
			ds.Diameter = (double)(2 * (int)(1000.0 * RevitUtils.DistanceToInternal(conn.Radius)));
			RevitUtils.FlowToInternal(conn.Flow);
			return true;
		}

		private static Schema CreateSprinklerSchema(Autodesk.Revit.DB.Document doc, Guid schemaGuid, double obj)
		{
			Schema schema = Schema.Lookup(schemaGuid);
			if (schema == null)
			{
				Transaction transaction = new Transaction(doc, "CreateSprinlerSchema");
				try
				{
					transaction.Start();
					SchemaBuilder schemaBuilder = new SchemaBuilder(schemaGuid);
					schemaBuilder.SetReadAccessLevel((AccessLevel)1);
					schemaBuilder.SetWriteAccessLevel((AccessLevel)1);
					schemaBuilder.SetSchemaName("SprinklerExtensibleData");
					schemaBuilder.AddSimpleField("SprinklerFlow", typeof(double)).SetUnitType(37);
					schema = schemaBuilder.Finish();
					transaction.Commit();
				}
				catch
				{
					transaction.RollBack();
				}
			}
			return schema;
		}

		public static bool WriteFlowToSprinkler(Element elem, double flow)
		{
			bool result = false;
			Document document = elem.Document;
			Transaction transaction = new Transaction(document, "WriteExtensibleStorage");
			Schema schema = RevitUtils.CreateSprinklerSchema(document, RevitUtils.guidOfSprinklerSchema, flow);
			if (schema != null && schema.SchemaName == "SprinklerExtensibleData")
			{
				try
				{
					transaction.Start();
					Entity entity = new Entity(schema);
					Field field = schema.GetField("SprinklerFlow");
					entity.Set<double>(field, flow, (Autodesk.Revit.DB.DisplayUnitType)64);
					elem.SetEntity(entity);
					transaction.Commit();
					result = true;
				}
				catch
				{
					transaction.RollBack();
				}
			}
			return result;
		}

		public static double ReadFlowFromSrpinkler(Element elem)
		{
			double result = 0.0;
			Document document = elem.Document;
			Schema schema = Schema.Lookup(RevitUtils.guidOfSprinklerSchema);
			if (schema != null && schema.SchemaName == "SprinklerExtensibleData")
			{
				try
				{
					Entity entity = elem.GetEntity(schema);
					if (entity != null && entity.IsValid())
					{
						result = entity.Get<double>(schema.GetField("SprinklerFlow"), (Autodesk.Revit.DB.DisplayUnitType)64);
					}
				}
				catch
				{
				}
			}
			return result;
		}

		public static double Tol = 0.1;

		public static readonly Guid guidOfSprinklerSchema = new Guid("FCD17400-66EF-442C-A5ED-24953123520F");
	}
}
